/**
 * @file mechanoid.cpp
 * @author trevrasher
 * @brief 
 * @version 0.1
 * @date 2024-05-7
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include "mechanoid.h"

#include <QGraphicsSceneMouseEvent>
#include <QWheelEvent>
#include <QGraphicsEllipseItem>
#include <QGraphicsRectItem>
#include <QGraphicsPathItem>
#include <QGraphicsTextItem>
#include <QGuiApplication>
#include <QPalette>
#include <cmath>
#include <iostream>

mechanoid::mechanoid(QWidget* parent)
    : QGraphicsView(parent), _scene(new QGraphicsScene(this))
{
    setScene(_scene);
}
/**
 * @brief Преобразование целого числа в цвет.
 * 
 * @param colorCode Код цвета.
 * @return QColor Цвет.
 */
QColor mechanoid::intToColor(int colorCode)
{
    // Пример преобразования числа в цвет
    switch (colorCode) {
        case 1: return QColorConstants::Svg::red;
        case 2: return QColorConstants::Svg::green;
        case 3: return QColorConstants::Svg::blue;
        case 4: return QColorConstants::Svg::yellow;
        case 5: return QColorConstants::Svg::orange;
        case 6: return QColorConstants::Svg::purple;
        case 7: return QColorConstants::Svg::brown;
        case 8: return QColorConstants::Svg::cyan;
        default: return Qt::gray;
    }
}
/**
 * @brief Создание графической фигуры в зависимости от типа.
 * 
 * @param shapeType Тип фигуры.
 * @param color Цвет фигуры.
 * @param x Координата x.
 * @param y Координата y.
 * @return QGraphicsItem* Указатель на созданный объект фигуры.
 */
QGraphicsItem* mechanoid::intToShape(int shapeType, int size, QColor color, qreal x, qreal y)
{
    // Создаем объект фигуры в зависимости от типа фигуры
    QGraphicsItem* shapeItem = nullptr;

    // Ловим случай отрицательного ввода
    if (size < 0) {
        return nullptr;
    }

    switch (shapeType) {
        case 1: {
            // Созданием путь для круга
            QPainterPath circlePath;
            circlePath.addEllipse(x - size, y - size, size * 2, size * 2);
            shapeItem = new QGraphicsPathItem(circlePath);
            break;
        }
        case 2: {
            // Созданием путь для квадрата
            QPainterPath squarePath;
            squarePath.addRect(x - size, y - size, size * 2, size * 2);
            shapeItem = new QGraphicsPathItem(squarePath);
            break;
        }
        case 3: {
            // Созданием путь для звезды
            // =========TBD=========
            QPainterPath starPath;
            int outerRadius = 7;
            int innerRadius = 5;
            int numPoints = 5;
            double angle = 2 * M_PI / (2 * numPoints);
            for (int i = 0; i < 2 * numPoints; ++i) {
                int radius = (i % 2 == 0) ? outerRadius : innerRadius;
                double px = x + radius * sin(i * angle); // Сдвигаем точку на x вправо
                double py = y + radius * cos(i * angle); // Сдвигаем точку на y вниз
                if (i == 0) {
                    starPath.moveTo(px, py);
                } else {
                    starPath.lineTo(px, py);
                }
            }
            starPath.closeSubpath();

            shapeItem = new QGraphicsPathItem(starPath);
            break;
        }
        case 4: {
            // Создаем путь для треугольника
            QPainterPath trianglePath;
            trianglePath.moveTo(x, y - size);          
            trianglePath.lineTo(x - size, y + size * 2); 
            trianglePath.lineTo(x + size, y + size * 2); 
            trianglePath.closeSubpath();        

            shapeItem = new QGraphicsPathItem(trianglePath);
            break;
        }
        }   

    if (shapeItem && shapeItem->type() == QGraphicsPathItem::Type) {
        QGraphicsPathItem* pathItem = dynamic_cast<QGraphicsPathItem*>(shapeItem);
        if (pathItem) {
            QBrush brush(color);
            pathItem->setBrush(brush);
        }
    }

    // Добавляем созданный объект на сцену
    _scene->addItem(shapeItem);

    return shapeItem;
}

/**
 * @brief Инициализация сцены.
 * 
 * @param width Ширина сцены.
 * @param height Высота сцены.
 */
void mechanoid::handleInitialization(int width, int height)
{
    // Проверяем, что размеры прямоугольника сцены корректны
    if (width <= 0 || height <= 0) {
        std::cerr << "Error: Invalid scene dimensions. Width and height must be positive." << std::endl;
        return;
    }

    setMinimumSize(width * 4, height * 4);

    _scene->clear();
    _points.clear();
    _points_settings.clear();
    _points_labels.clear();
    _valid_points_names.clear();

    // Размер сцены
    QRectF scene(-width, -height, width * 2, height * 2);

    // Центрируем сцену относительно прямоугольника
    centerOn(scene.center());

    // Масштабируем сцену, чтобы видеть только область с заданными размерами
    fitInView(scene, Qt::KeepAspectRatio);

}

/**
 * @brief Добавление точки на сцену.
 * 
 * @param point_name Идентификатор точки.
 * @param x Координата x точки.
 * @param y Координата y точки.
 */
void mechanoid::handleAddPoint(const QString& point_name, float x, float y)
{
    handleRemovePoint(point_name);

    // Получаем настройки отображения для точки с идентификатором
    SeriesSettings settings = _points_settings.value(point_name);  

    QGraphicsItem* figure = intToShape(settings.shape, settings.size, settings.color, x, y);
    if (!figure) {
        return;
    }
    // Добавляем фигуру
    _points.insert(point_name, figure);

    if (!_valid_points_names.contains(point_name)) {
        return;
    }
    // Выводим идентификатор точки
    QGraphicsTextItem* textItem = new QGraphicsTextItem(point_name);
    textItem->setDefaultTextColor(Qt::black); // Устанавливаем цвет текста
    textItem->setPos(x, y - settings.size); // Устанавливаем позицию текста
    QFont font = textItem->font(); // Получаем текущий шрифт
    font.setPointSize(settings.size + 5);
    textItem->setFont(font); // Устанавливаем новый шрифт
    _scene->addItem(textItem);

    _points_labels.insert(point_name, textItem);
}

/**
 * @brief Добавление настроек для отображения.
 * 
 * @param point_name Идентификатор точки.
 * @param shapeType Тип формы.
 * @param size Размер фигуры.
 * @param colorCode Код цвета.
 */
void mechanoid::handleAddSettings(const QString& point_name, int shapeType, int size, int colorCode)
{
    // Преобразуем числа в цвет и тип формы
    QColor color = intToColor(colorCode);
    int shape = shapeType;

    // Сохраняем настройки серии
    _points_settings[point_name] = {shape, size, color};
}

/**
 * @brief Удаление точки со сцены.
 * 
 * @param point_name Идентификатор точки.
 */
void mechanoid::handleRemovePoint(const QString& point_name)
{
    // Получаем точку и удаляем ее со сцены
    QGraphicsItem* point = _points[point_name];
    if (point) {
        _scene->removeItem(point);
        delete point;
    }

    // Получаем идентификатор для точки и удаляем его со сцены
    QGraphicsTextItem* textItem = _points_labels[point_name];
    if (textItem) {
        _scene->removeItem(textItem);
        delete textItem;
    }

}

/**
 * @brief Включение отображения идентификатора точки.
 * 
 * @param point_name Идентификатор точки.
 */
void mechanoid::handleEnableLabelView(const QString& point_name)
{
    _valid_points_names.insert(point_name);
}

/**
 * @brief Отключение отображения идентификатора точки.
 * 
 * @param point_name Идентификатор точки.
 */
void mechanoid::handleDisableLabelView(const QString& point_name)
{
    _valid_points_names.remove(point_name);
}

/**
 * @brief Изменение размера точки по идентификатору.
 * 
 * @param point_name Идентификатор точки.
 * @param size Желаемый размер.
 */
void mechanoid::handleSetPointSize(const QString& point_name, int size)
{
    // Проверяем, существуют ли настройки для текущей точки
    if (!_points_settings.contains(point_name)) {
        std::cout << "Point " << point_name.toStdString() << "not found" << std::endl;
        return;
    }

    // Получаем настройки для данной точки
    SeriesSettings settings = _points_settings[point_name];

    // Обновляем размер фигуры в настройках
    settings.size = size;

    // Обновляем глобальное значение настроек серии
    _points_settings[point_name] = settings;

    // Обновляем фигуру на сцене
    QGraphicsItem* point = _points[point_name];
    if (point) {
        QPointF pos = point->pos(); // Получаем текущую позицию точки
        _scene->removeItem(point); // Удаляем старую фигуру
        delete point;

        // Создаем новую фигуру с обновленным размером и добавляем на сцену
        QGraphicsItem* newPoint = intToShape(settings.shape, settings.size, settings.color, pos.x(), pos.y());
        if (newPoint) {
            _points[point_name] = newPoint; // Обновляем указатель на фигуру
        }
    } else {
        std::cout << "Point " << point_name.toStdString() << "not found" << std::endl;
    }
}